package com.shoulder.boot.acl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shoulder.boot.acl.dto.MenuAddDTO;
import com.shoulder.boot.acl.dto.MenuModDTO;
import com.shoulder.boot.acl.entity.Menu;
import com.shoulder.boot.acl.entity.Role;
import com.shoulder.boot.acl.entity.RoleMenu;
import com.shoulder.boot.acl.enums.MenuEnums;
import com.shoulder.boot.acl.exception.AclException;
import com.shoulder.boot.acl.mapper.MenuMapper;
import com.shoulder.boot.acl.mapper.RoleMenuMapper;
import com.shoulder.boot.acl.mapper.UserRoleMapper;
import com.shoulder.boot.acl.service.MenuService;
import com.shoulder.boot.acl.vo.LeftMenuVo;
import com.shoulder.core.api.ApiUser;
import com.shoulder.core.utils.TokenUtils;
import com.shoulder.core.utils.TreeUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@Service
@Transactional
@AllArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final UserRoleMapper userRoleMapper;
    private final RoleMenuMapper roleMenuMapper;

    @Override
    public List<LeftMenuVo> me() {
        ApiUser user = TokenUtils.parseUser();
        if (user == null) {
            throw new AclException("当前登录人信息不存在");
        }

        List<Role> roles = userRoleMapper.findRolesByUserId(user.getId());
        if (CollectionUtils.isEmpty(roles)) {
            return Collections.emptyList();
        }
        List<String> roleIds = roles.stream().map(Role::getId).toList();
        List<Menu> menus = roleMenuMapper.findMenuByRoleIds(roleIds)
                .stream().filter(each -> each.getType() != MenuEnums.BUTTON.getCode()).toList();
        if (CollectionUtils.isEmpty(menus)) {
            return Collections.emptyList();
        }
        List<Menu> sortedMenus = menus.stream().sorted(Comparator.comparingInt(Menu::getType)).toList();
        List<LeftMenuVo> leftVos = LeftMenuVo.toLeftVos(sortedMenus);
//        return RecursionUtils.toList(MapUtils.bean2Map(leftVos), LeftMenuVo.class);
        return TreeUtils.build(leftVos, LeftMenuVo::getParentId, LeftMenuVo::getId, e -> "0".equals(e.getParentId()), LeftMenuVo::setChildren);
    }

    @Override
    public List<Menu> tree() {
        List<Menu> menus = this.baseMapper.selectList(new LambdaQueryWrapper<Menu>().orderByDesc(Menu::getCreateTime));
//        return RecursionUtils.toList(MapUtils.bean2Map(this.baseMapper.selectList(new LambdaQueryWrapper<Menu>()
//                .orderByDesc(Menu::getCreateTime))), Menu.class);
        return TreeUtils.build(menus, Menu::getParentId, Menu::getId, e -> "0".equals(e.getParentId()), Menu::setChildren);
    }

    @Override
    public void menuAdd(MenuAddDTO addDTO) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(addDTO, menu);
        this.baseMapper.insert(menu);
    }

    @Override
    public void menuMod(MenuModDTO modDTO) {
        Menu menu = this.baseMapper.selectById(modDTO.getId());
        if (menu == null) {
            throw new AclException("菜单不存在");
        }
        BeanUtils.copyProperties(modDTO, menu);
        this.baseMapper.updateById(menu);
    }

    @Override
    public void menuDel(String id) {
        Menu menu = this.baseMapper.selectById(id);
        if (menu == null) {
            throw new AclException("菜单不存在");
        }
        if (this.baseMapper.selectCount(new LambdaQueryWrapper<Menu>().eq(Menu::getParentId, id)) > 0) {
            throw new AclException("请先删除子菜单");
        }
        this.baseMapper.deleteById(id);
        roleMenuMapper.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getMenuId, id));
    }

    @Override
    public List<Menu> excludeButton() {
        List<Menu> menus = this.baseMapper.selectList(new LambdaQueryWrapper<Menu>()
                .ne(Menu::getType, MenuEnums.BUTTON.getCode())
                .orderByDesc(Menu::getCreateTime));
        return TreeUtils.build(menus, Menu::getParentId, Menu::getId, e -> "0".equals(e.getParentId()), Menu::setChildren);
    }
}